package com.mazaiting.rtda.heap;

import com.mazaiting.classfile.ClassFile;
import com.mazaiting.rtda.MtSlots;
import lombok.Getter;
import lombok.Setter;

import java.util.Objects;

/**
 * 使用结构体来表示将要放进方法区内的类
 *
 * @author mazaiting
 * @since 2021/8/16
 */
@Setter
@Getter
public class MtClass {
    /**
     * 类的访问标志，总共16比特。字段和方法也有访问标志，但具体标志位的含义可能有所不同
     */
    private short accessFlags;
    /**
     * 类名
     * 完全限定名
     */
    private String name;
    /**
     * 父类名
     * 完全限定名
     */
    private String superClassName;
    /**
     * 接口名
     * 完全限定名
     */
    private String[] interfaceNames;
    /**
     * 运行时常量池
     */
    private MtConstantPool constantPool;
    /**
     * 字段表
     */
    private MtField[] fields;
    /**
     * 方法表
     */
    private MtMethod[] methods;
    /**
     * 类加载器
     */
    private MtClassloader loader;
    /**
     * 超类
     */
    private MtClass superClass;
    /**
     * 接口类数组
     */
    private MtClass[] interfaces;
    /**
     * 实例变量占据的空间大小
     */
    private int instanceSlotCount;
    /**
     * 类变量占据的空间大小
     */
    private int staticSlotCount;
    /**
     * 静态变量
     */
    private MtSlots staticVars;
    /**
     * 标识类是否已经初始化
     * 类的<clinit>方法是否已经开始执行
     */
    private boolean initStarted;

    public MtClass(ClassFile classFile) {
        // 设置权限
        this.accessFlags = classFile.getAccessFlags();
        // 设置类名
        this.name = classFile.getClassName();
        // 获取父类名
        this.superClassName = classFile.getSuperClassName();
        // 获取接口名
        this.interfaceNames = classFile.getInterfaceNames();
        // 设置常量池
        this.constantPool = new MtConstantPool(this, classFile.getConstantPool());
        // 设置字段
        this.fields = MtField.newFields(this, classFile.getFields());
        // 设置方法
        this.methods = MtMethod.newMethods(this, classFile.getMethods());
    }

    /**
     * 判断是否为公共
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isPublic() {
        return MtAccessFlags.isPublic(accessFlags);
    }

    /**
     * 判断是否为final
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isFinal() {
        return MtAccessFlags.isFinal(accessFlags);
    }

    /**
     * 判断是否为父类
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isSuper() {
        return MtAccessFlags.isSuper(accessFlags);
    }

    /**
     * 判断是否为接口
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isInterface() {
        return MtAccessFlags.isInterface(accessFlags);
    }

    /**
     * 判断是否为抽象
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isAbstract() {
        return MtAccessFlags.isAbstract(accessFlags);
    }

    /**
     * 判断是否为Synthetic
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isSynthetic() {
        return MtAccessFlags.isSynthetic(accessFlags);
    }

    /**
     * 判断是否为注解
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isAnnotation() {
        return MtAccessFlags.isAnnotation(accessFlags);
    }

    /**
     * 判断是否为枚举
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isEnum() {
        return MtAccessFlags.isEnum(accessFlags);
    }

    /**
     * 判断是否有访问权限
     *
     * @param other 待访问的类
     * @return true: 可访问; false: 不可访问
     */
    public boolean isAccessibleTo(MtClass other) {
        return isPublic() || Objects.equals(getPackageName(), other.getPackageName());
    }

    /**
     * 获取包名
     *
     * @return 包名
     */
    public String getPackageName() {
        int num = name.lastIndexOf("/");
        if (num > 0) {
            return name.substring(0, num);
        }
        return "";
    }

    /**
     * 判断是否为子类
     *
     * @param mtClass 类实例
     * @return true: 子类; false: 非子类
     */
    public boolean isSubClassOf(MtClass mtClass) {
        for (MtClass tmpClass = superClass; Objects.nonNull(tmpClass); tmpClass = tmpClass.getSuperClass()) {
            if (Objects.equals(tmpClass, mtClass)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 创建对象
     *
     * @return 对象
     */
    public MtObject newObject() {
        return new MtObject(this);
    }

    /**
     * 判断参数类是否当前对象的实例
     *
     * @param mtClass 类实例
     * @return true: 是; false: 非子类实例
     */
    public boolean isAssignableFrom(MtClass mtClass) {
        if (Objects.equals(this, mtClass)) {
            return true;
        }
        // 判断是否接口
        if (!isInterface()) {
            return mtClass.isSubClassOf(this);
        } else {
            return mtClass.isImplements(this);
        }
    }

    /**
     * 判断是否实现接口
     *
     * @param mtClass 类实例
     * @return true: 实现; false: 未实现
     */
    public boolean isImplements(MtClass mtClass) {
        for (MtClass tmpClass = this; Objects.nonNull(tmpClass); tmpClass = tmpClass.getSuperClass()) {
            for (MtClass tmpClassInterface : tmpClass.getInterfaces()) {
                if (Objects.equals(mtClass, tmpClassInterface) || tmpClassInterface.isSubInterfaceOf(mtClass)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否为子接口
     *
     * @param mtClass 类实例
     * @return true: 是; false: 否
     */
    private boolean isSubInterfaceOf(MtClass mtClass) {
        for (MtClass anInterface : getInterfaces()) {
            if (Objects.equals(anInterface, mtClass) || anInterface.isSubInterfaceOf(mtClass)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断某个类是否为当前类的子类
     * @param other 某个类
     * @return true: 是; false: 否
     */
    public boolean isSuperClassOf(MtClass other) {
        return other.isSubClassOf(this);
    }

    /**
     * 获取主函数
     *
     * @return 主函数
     */
    public MtMethod getMainMethod() {
        return getStaticMethod("main", "([Ljava/lang/String;)V");
    }

    /**
     * 获取静态方法
     *
     * @param methodName 方法名
     * @param descriptor 方法描述
     * @return 方法
     */
    private MtMethod getStaticMethod(String methodName, String descriptor) {
        for (MtMethod method : getMethods()) {
            // 判断静态, 方法名, 方法描述
            if (method.isStatic() && Objects.equals(method.getName(), methodName) && Objects.equals(method.getDescriptor(), descriptor)) {
                return method;
            }
        }
        return null;
    }

    /**
     * 开始初始化
     */
    public void startInit() {
        this.initStarted = true;
    }

    @Override
    public String toString() {
        return "MtClass{" +
                "name='" + name + '\'' +
                ", superClassName='" + superClassName + '\'' +
                '}';
    }

    /**
     * 获取 <clinit> 方法
     * @return <clinit> 方法
     */
    public MtMethod getClInitMethod() {
        return getStaticMethod("<clinit>", "()V");
    }
}


















